
/*
iverilog 构建测试命令
iverilog ppu_test3.v ppu2.v && vvp -M./M -mlcd_show a.out

*/

module srama(
    addr,
    dat,
    rw,
    rd,
    dat_out,
);
    input wire[13:0] addr;
    inout wire[7:0] dat;
    input wire rw;
    input wire rd;
    output reg [7:0] dat_out = 'd0;
    assign dat =
    (rw&~rd)?dat_out:8'hzz;
    ;
    reg [7:0] mem[0:'h3fff];
    integer i;
    integer x;
    initial begin
        $readmemh("D:\\src\\fpga\\fpxnes\\ppu_mario.hex",mem);
    end

    always @(negedge rd) begin
        dat_out <= mem[addr[13:0]];
    end

    always @(negedge rw) begin
        mem[addr[13:0]] <= dat;
    end

endmodule

module sram (
    input wire[13:0] addra,
    output wire[7:0] doa,
    input wire clka,
    input wire rsta
);
    reg [7:0] mem[0:'h3fff];
    integer i;
    integer x;
    initial begin
        $readmemh("D:\\src\\fpga\\fpxnes\\ppu_mario.hex",mem);
    end
    assign doa = dat_reg;
    reg[7:0] dat_reg = 'd0;

    always @(posedge clka) begin
        dat_reg <= mem[addra[13:0]];
    end
endmodule

module ppu_test2(
    ppu_addr,
    ppu_dat,
    ppu_rw,
    ppu_rd,
    ppu_clk,
    ppu_nmi,
    dat_out,
    out_pixel,
);
    output wire[13:0] ppu_addr;
    output wire ppu_rw;
    output wire ppu_rd;
    output wire[7:0] ppu_dat;
    input wire ppu_clk;
    output wire ppu_nmi;
    output reg[7:0] dat_out;
    output wire[5:0] out_pixel;

    wire[2:0] cpu_addr = 'd0;
    wire[7:0] cpu_dat;
    wire cpu_rw = 1'b1;
    wire ppu_cs = 'b1;

    reg[15:0]count = 'd0;

    // srama ppu_sram(
    //     ppu_addr,
    //     ppu_dat,
    //     ppu_rw,
    //     ppu_rd,
    //     dat_out,
    // );
    wire[7:0] R,G,B;
    reg [7:0] pal_R['h3f:0];
    reg [7:0] pal_G['h3f:0];
    reg [7:0] pal_B['h3f:0];
    assign R = pal_R[out_pixel];
    assign G = pal_G[out_pixel];
    assign B = pal_B[out_pixel];
    initial begin
        pal_R['h00] <= 'h0C * 8;pal_B['h00] <= 'h0C * 8;pal_G['h00] <= 'h0C * 8;
        pal_R['h01] <= 'h00 * 8;pal_B['h01] <= 'h10 * 8;pal_G['h01] <= 'h04 * 8;
        pal_R['h02] <= 'h00 * 8;pal_B['h02] <= 'h18 * 8;pal_G['h02] <= 'h00 * 8;
        pal_R['h03] <= 'h0C * 8;pal_B['h03] <= 'h18 * 8;pal_G['h03] <= 'h08 * 8;
        pal_R['h04] <= 'h10 * 8;pal_B['h04] <= 'h0C * 8;pal_G['h04] <= 'h00 * 8;
        pal_R['h05] <= 'h14 * 8;pal_B['h05] <= 'h0C * 8;pal_G['h05] <= 'h00 * 8;
        pal_R['h06] <= 'h14 * 8;pal_B['h06] <= 'h00 * 8;pal_G['h06] <= 'h04 * 8;
        pal_R['h07] <= 'h10 * 8;pal_B['h07] <= 'h00 * 8;pal_G['h07] <= 'h08 * 8;
        pal_R['h08] <= 'h0C * 8;pal_B['h08] <= 'h00 * 8;pal_G['h08] <= 'h08 * 8;
        pal_R['h09] <= 'h04 * 8;pal_B['h09] <= 'h00 * 8;pal_G['h09] <= 'h08 * 8;
        pal_R['h0A] <= 'h00 * 8;pal_B['h0A] <= 'h04 * 8;pal_G['h0A] <= 'h0C * 8;
        pal_R['h0B] <= 'h00 * 8;pal_B['h0B] <= 'h00 * 8;pal_G['h0B] <= 'h10 * 8;
        pal_R['h0C] <= 'h00 * 8;pal_B['h0C] <= 'h08 * 8;pal_G['h0C] <= 'h08 * 8;
        pal_R['h0D] <= 'h00 * 8;pal_B['h0D] <= 'h00 * 8;pal_G['h0D] <= 'h00 * 8;
        pal_R['h0E] <= 'h00 * 8;pal_B['h0E] <= 'h00 * 8;pal_G['h0E] <= 'h00 * 8;
        pal_R['h0F] <= 'h00 * 8;pal_B['h0F] <= 'h00 * 8;pal_G['h0F] <= 'h00 * 8;
        pal_R['h10] <= 'h14 * 8;pal_B['h10] <= 'h14 * 8;pal_G['h10] <= 'h14 * 8;
        pal_R['h11] <= 'h00 * 8;pal_B['h11] <= 'h18 * 8;pal_G['h11] <= 'h0C * 8;
        pal_R['h12] <= 'h00 * 8;pal_B['h12] <= 'h1C * 8;pal_G['h12] <= 'h08 * 8;
        pal_R['h13] <= 'h10 * 8;pal_B['h13] <= 'h1C * 8;pal_G['h13] <= 'h00 * 8;
        pal_R['h14] <= 'h14 * 8;pal_B['h14] <= 'h1C * 8;pal_G['h14] <= 'h00 * 8;
        pal_R['h15] <= 'h1C * 8;pal_B['h15] <= 'h10 * 8;pal_G['h15] <= 'h00 * 8;
        pal_R['h16] <= 'h1C * 8;pal_B['h16] <= 'h00 * 8;pal_G['h16] <= 'h00 * 8;
        pal_R['h17] <= 'h18 * 8;pal_B['h17] <= 'h00 * 8;pal_G['h17] <= 'h0C * 8;
        pal_R['h18] <= 'h10 * 8;pal_B['h18] <= 'h00 * 8;pal_G['h18] <= 'h0C * 8;
        pal_R['h19] <= 'h04 * 8;pal_B['h19] <= 'h00 * 8;pal_G['h19] <= 'h10 * 8;
        pal_R['h1A] <= 'h00 * 8;pal_B['h1A] <= 'h00 * 8;pal_G['h1A] <= 'h10 * 8;
        pal_R['h1B] <= 'h00 * 8;pal_B['h1B] <= 'h0C * 8;pal_G['h1B] <= 'h14 * 8;
        pal_R['h1C] <= 'h00 * 8;pal_B['h1C] <= 'h10 * 8;pal_G['h1C] <= 'h10 * 8;
        pal_R['h1D] <= 'h00 * 8;pal_B['h1D] <= 'h00 * 8;pal_G['h1D] <= 'h00 * 8;
        pal_R['h1E] <= 'h00 * 8;pal_B['h1E] <= 'h00 * 8;pal_G['h1E] <= 'h00 * 8;
        pal_R['h1F] <= 'h00 * 8;pal_B['h1F] <= 'h00 * 8;pal_G['h1F] <= 'h00 * 8;
        pal_R['h20] <= 'h1C * 8;pal_B['h20] <= 'h1C * 8;pal_G['h20] <= 'h1C * 8;
        pal_R['h21] <= 'h0C * 8;pal_B['h21] <= 'h1C * 8;pal_G['h21] <= 'h14 * 8;
        pal_R['h22] <= 'h10 * 8;pal_B['h22] <= 'h1C * 8;pal_G['h22] <= 'h10 * 8;
        pal_R['h23] <= 'h18 * 8;pal_B['h23] <= 'h1C * 8;pal_G['h23] <= 'h0C * 8;
        pal_R['h24] <= 'h1C * 8;pal_B['h24] <= 'h1C * 8;pal_G['h24] <= 'h00 * 8;
        pal_R['h25] <= 'h1C * 8;pal_B['h25] <= 'h1C * 8;pal_G['h25] <= 'h0C * 8;
        pal_R['h26] <= 'h1C * 8;pal_B['h26] <= 'h00 * 8;pal_G['h26] <= 'h10 * 8;
        pal_R['h27] <= 'h1C * 8;pal_B['h27] <= 'h00 * 8;pal_G['h27] <= 'h14 * 8;
        pal_R['h28] <= 'h18 * 8;pal_B['h28] <= 'h00 * 8;pal_G['h28] <= 'h18 * 8;
        pal_R['h29] <= 'h0C * 8;pal_B['h29] <= 'h00 * 8;pal_G['h29] <= 'h18 * 8;
        pal_R['h2A] <= 'h00 * 8;pal_B['h2A] <= 'h00 * 8;pal_G['h2A] <= 'h1C * 8;
        pal_R['h2B] <= 'h08 * 8;pal_B['h2B] <= 'h18 * 8;pal_G['h2B] <= 'h1C * 8;
        pal_R['h2C] <= 'h00 * 8;pal_B['h2C] <= 'h1C * 8;pal_G['h2C] <= 'h1C * 8;
        pal_R['h2D] <= 'h00 * 8;pal_B['h2D] <= 'h00 * 8;pal_G['h2D] <= 'h00 * 8;
        pal_R['h2E] <= 'h00 * 8;pal_B['h2E] <= 'h00 * 8;pal_G['h2E] <= 'h00 * 8;
        pal_R['h2F] <= 'h00 * 8;pal_B['h2F] <= 'h00 * 8;pal_G['h2F] <= 'h00 * 8;
        pal_R['h30] <= 'h1C * 8;pal_B['h30] <= 'h1C * 8;pal_G['h30] <= 'h1C * 8;
        pal_R['h31] <= 'h14 * 8;pal_B['h31] <= 'h1C * 8;pal_G['h31] <= 'h18 * 8;
        pal_R['h32] <= 'h18 * 8;pal_B['h32] <= 'h1C * 8;pal_G['h32] <= 'h14 * 8;
        pal_R['h33] <= 'h1C * 8;pal_B['h33] <= 'h1C * 8;pal_G['h33] <= 'h14 * 8;
        pal_R['h34] <= 'h1C * 8;pal_B['h34] <= 'h1C * 8;pal_G['h34] <= 'h10 * 8;
        pal_R['h35] <= 'h1C * 8;pal_B['h35] <= 'h14 * 8;pal_G['h35] <= 'h14 * 8;
        pal_R['h36] <= 'h1C * 8;pal_B['h36] <= 'h10 * 8;pal_G['h36] <= 'h18 * 8;
        pal_R['h37] <= 'h1C * 8;pal_B['h37] <= 'h08 * 8;pal_G['h37] <= 'h1C * 8;
        pal_R['h38] <= 'h1C * 8;pal_B['h38] <= 'h0C * 8;pal_G['h38] <= 'h1C * 8;
        pal_R['h39] <= 'h14 * 8;pal_B['h39] <= 'h08 * 8;pal_G['h39] <= 'h1C * 8;
        pal_R['h3A] <= 'h10 * 8;pal_B['h3A] <= 'h0C * 8;pal_G['h3A] <= 'h1C * 8;
        pal_R['h3B] <= 'h08 * 8;pal_B['h3B] <= 'h18 * 8;pal_G['h3B] <= 'h1C * 8;
        pal_R['h3C] <= 'h10 * 8;pal_B['h3C] <= 'h1C * 8;pal_G['h3C] <= 'h18 * 8;
        pal_R['h3D] <= 'h00 * 8;pal_B['h3D] <= 'h00 * 8;pal_G['h3D] <= 'h00 * 8;
        pal_R['h3E] <= 'h00 * 8;pal_B['h3E] <= 'h00 * 8;pal_G['h3E] <= 'h00 * 8;
        pal_R['h3F] <= 'h00 * 8;pal_B['h3F] <= 'h00 * 8;pal_G['h3F] <= 'h00 * 8;
    end

    always @(posedge ppu_clk) begin
        $lcd(x,y,R,G,B);
    end

    assign ppu_dat = (~ppu_rd&ppu_rw)?rom_dat:'hzz;
    wire[7:0] rom_dat;
    sram ppu_sram(
        .doa    (rom_dat),
        .addra  (ppu_addr),
        .clka   (ppu_clk),
        .rsta   (1'b0)
    );
    always @(negedge ppu_rd) begin
        dat_out <= rom_dat;
    end

    wire[8:0] x;
    wire[8:0] y;

    ppu ppua(
        ppu_addr,
        ppu_dat,
        ppu_clk,
        ppu_rw,
        ppu_rd,

        ppu_cs,
        ppu_nmi,

        //cpu接口
        cpu_addr,
        cpu_dat,
        cpu_rw,

        //输出像素
        out_pixel,
        x,
        y,
        1'b1,
    );

endmodule

module iverilog_test (
);

    reg clk = 'd0;
    always #10 clk = ~clk;
    reg[24:0] counter = 'd0;
    always @(posedge clk) begin
        counter <= counter + 1;
        if(counter>342*300)begin
            $finish;
        end
    end

    output wire[13:0] ppu_addr;
    wire[7:0]  ppu_dat;
    wire ppu_rw;
    wire ppu_rd;
    wire ppu_nmi;
    wire[7:0] dat_out;
    wire[5:0] out_pixel;

    ppu_test2 ptest(
        ppu_addr,
        ppu_dat,
        ppu_rw,
        ppu_rd,
        clk,
        ppu_nmi,
        dat_out,
        out_pixel,
    );

    initial begin
        $dumpfile("wave.vcd");
        $dumpvars(0,iverilog_test);
    end

endmodule
